#include<pthread.h>
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

#define LENGTH 10
FILE *readFile;
FILE *writeFile;
int countr=0;
int countw=0;
int semid;
int shmid;
int flag=1;
int pid1;
int pid2;
void P(int semid,int index){//对信号集合中index信号进行P操作
    struct sembuf sem;
    sem.sem_num=index;
    sem.sem_op=-1;
    sem.sem_flg=0;
    semop(semid,&sem,1);
    return;
}

void V(int semid,int index){//对信号集合中index信号进行V操作
     struct sembuf sem;
     sem.sem_num=index;
     sem.sem_op=1;
     sem.sem_flg=0;
     semop(semid,&sem,1);
     return;
}
 
int initSem(int semid,int index,int val){
    return semctl(semid,index,SETVAL,val);
}
//第0个信号量是读操作
//第一个信号量是写操作
void readChild(){//将文件内容读到共享内存中
    char*head=(char*)shmat(shmid,0,0);
    int index=0;
    char get;
    int putnum=0;
    while(1){
        //fread(&get,sizeof(char),1,readFile);
        get = fgetc(readFile);
        P(semid,1);
        P(semid,0);
        head[index]=get;
        index++;
        putnum++;
        if(putnum%10==0){
            printf("放进缓冲区 %d个字节\n",putnum);
        }
        index=index%LENGTH;
        V(semid,0);
        V(semid,2);
        if(get==EOF){
          printf("一共放进缓冲区%d 个字节\n",putnum);
          break;
        }
    }
    
}
void writeChild(){
    char *head=(char*)shmat(shmid,0,0);
    int index=0;
    int writenum=0;
    char get;
    while(1){
        P(semid,2);
        P(semid,0);
        get=head[index];
        index++;
        index=index%LENGTH;
        writenum++;
        V(semid,0);
        V(semid,1);
        if(get==EOF){
           break;
        }
        fputc(get,writeFile);
        printf("向输出文件写进第%d 个字节\n",writenum);
    }
}

int main(int argc,char*arg[]){
    if(argc!=3){
        printf("参数错误。\n");
        return 0;
    }
    readFile=fopen(arg[1],"rb");
    writeFile=fopen(arg[2],"wb");
    if(readFile==NULL||writeFile==NULL){
        printf("打开文件错误。\n");
        return 0;
    }
    // 申请信号量
    semid=semget(IPC_PRIVATE,3,IPC_PRIVATE|0666);
    //0号信号量表示读写锁，1号信号量表示空余位置，2号信号量表示已有位置
    initSem(semid,0,1);
    initSem(semid,1,10);
    initSem(semid,2,0);

    // 申请共享内存
    shmid=shmget(IPC_PRIVATE,(LENGTH)*sizeof(char),0666|IPC_CREAT);
    pid1=fork();
    if(pid1==0) {
        readChild();
        printf("读操作退出\n");
        exit(0);
    }
    pid2=fork();
    if(pid2==0){
        sleep(0.1);
        writeChild();
        printf("写操作退出\n");
        exit(0);
    }
    waitpid(pid1,NULL,0);
    waitpid(pid2,NULL,0);
    printf("复制完成！\n");

    //删除信号量
    semctl(semid,IPC_RMID,0);
    shmctl(shmid,IPC_RMID,0);
    fclose(readFile);
    fclose(writeFile);
    return 0;
} 
